package com.dcivision.dms.taglib;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TryCatchFinally;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsRoot;
import com.dcivision.dms.bean.DmsTreeNode;
import com.dcivision.dms.core.DmsTreeController;
import com.dcivision.dms.core.DocumentRetrievalManager;
import com.dcivision.dms.core.DocumentValidateManager;
import com.dcivision.dms.dao.DmsRootDAObject;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;

public class DmsTreeTag extends BodyTagSupport implements TryCatchFinally {

  private Log log = new LogFactoryImpl().getInstance(this.getClass());

  private String name = null;

  private Integer rootId = null;

  private Integer expandId = null;

  private Integer rootStartId = null;

  private String rootType = null;

  private Integer ownerId = null;

  private String permission = null;

  private String cookie = null;

  private String checkbox = null;

  private String textClickOpen = null;

  private String textClickClose = null;

  //out member
  private StringBuffer sbJstCode = null;

  private StringBuffer sbDivCode = null;

  //local member
  private SessionContainer sessionContainer = null;

  private Connection dbConn = null;

  private boolean[] aIndent = null;

  private int nodeIndex = 0;

  private String coOpenIds = null; //record open id cookies

  private String coCheckId = null; //record checked id cookie; no avaliable now.

  private List expandParentIds = null;

  private List rootStartParentIds = null;

  private Map mImageIcon = null;

  public int doStartTag() throws JspException {
    try {
      this.doInitTag();
      this.generateCode();
      pageContext.getOut().print(this.sbDivCode.toString()+"\n");
      pageContext.getOut().print(this.sbJstCode.toString()+"\n");
      return(SKIP_BODY);
    } catch (Exception e) {
      log.error(e, e);
      throw new JspException(e);
    }
  }

  public int doEndTag() throws JspException {
    this.release();//Add By Jim Zhou        2006/12/25      EIP-777
    return EVAL_PAGE;
  }

  private void doInitTag() throws Exception {
    this.sessionContainer = this.getSessionContainer();
    this.sbDivCode = new StringBuffer();
    this.sbJstCode = new StringBuffer();
    this.aIndent = new boolean[100];
    this.sbJstCode = new StringBuffer();
    this.sbDivCode = new StringBuffer();

    this.coCheckId = "";
    this.coOpenIds = "";
    this.nodeIndex = 0;
    this.expandParentIds = new ArrayList();
    this.rootStartParentIds = new ArrayList();
    if (this.permission == null || this.permission.equals("true") || this.permission.equals("enable")) {
      this.permission = "true";
    }else {
      this.permission = "false";
    }
    if (this.cookie == null || this.cookie.equals("true") || this.cookie.equals("enable")) {
      this.cookie = "true";
      this.setCookies(((HttpServletRequest)this.pageContext.getRequest()).getCookies());
    }else {
      this.cookie = "false";
    }
    if (this.textClickOpen == null || this.textClickOpen.equals("false") || this.textClickOpen.equals("disable")) {
      this.textClickOpen = "false";
    }else {
      this.textClickOpen = "true";
    }
    if (this.textClickClose == null || this.textClickClose.equals("false") || this.textClickClose.equals("disable")) {
      this.textClickClose = "false";
    }else {
      this.textClickClose = "true";
    }
    if (this.checkbox == null || this.checkbox.equals("false") || this.checkbox.equals("disable")) {
      this.checkbox = "false";
    }else {
      this.checkbox = "true";
    }

    String contextPath = (String)this.pageContext.getServletContext().getAttribute(GlobalConstant.CONTEXT_PATH_KEY);
    String preference = SystemParameterFactory.getSystemParameter(SystemParameterConstant.PREFERENCE);
    if ((sessionContainer!=null) && (sessionContainer.getUserRecord()!=null)) {
      if (sessionContainer.getUserRecord().getPreference()!=null) {
        preference = sessionContainer.getUserRecord().getPreference().toString();
      }
    }
    String imgPath = contextPath + "/theme/pref" + preference + "/img/common/";
    mImageIcon = new HashMap();
    mImageIcon.put("root", imgPath+"IconDMSTreeRoot.gif");
    mImageIcon.put("rootOpen", imgPath+"IconDMSTreeRoot.gif");
    mImageIcon.put("folder", imgPath+"IconTreeFolderClosed.gif");
    mImageIcon.put("folderOpen", imgPath+"IconTreeFolderOpened.gif");
    mImageIcon.put("compound", imgPath+"IconTreeCompoundClosed.gif");
    mImageIcon.put("compoundOpen", imgPath+"IconTreeCompoundOpened.gif");
    mImageIcon.put("paper", imgPath+"IconTreePaperDocClose.gif");
    mImageIcon.put("paperOpen", imgPath+"IconTreePaperDocOpen.gif");
    mImageIcon.put("email", imgPath+"IconTreeEmailDocClose.gif");
    mImageIcon.put("emailOpen", imgPath+"IconTreeEmailDocOpen.gif");
    mImageIcon.put("form", imgPath+"IconTreeFormDocClose.gif");
    mImageIcon.put("formOpen", imgPath+"IconTreeFormDocOpen.gif");
    mImageIcon.put("workflow", imgPath+"IconTreeFlowDocClose.gif");
    mImageIcon.put("workflowOpen", imgPath+"IconTreeFlowDocOpen.gif");
    mImageIcon.put("shortcut", imgPath+"IconDMSFolderShortcut.gif");
    mImageIcon.put("file", imgPath+"IconTreeFile.gif");
    mImageIcon.put("empty", imgPath+"IconTreeBlank.gif");
    mImageIcon.put("line", imgPath+"IconTreeI.gif");
    mImageIcon.put("join", imgPath+"IconTreeT.gif");
    mImageIcon.put("joinbottom", imgPath+"IconTreeL.gif");
    mImageIcon.put("plus", imgPath+"IconTreeTPlus.gif");
    mImageIcon.put("plusbottom", imgPath+"IconTreeLPlus.gif");
    mImageIcon.put("minus", imgPath+"IconTreeTMinus.gif");
    mImageIcon.put("minusbottom", imgPath+"IconTreeLMinus.gif");
  }

  private void generateCode() throws Exception {
    this.dbConn = DataSourceFactory.getConnection();
    try {
      if (this.rootType == null || this.ownerId == null) {
        DmsRootDAObject dmsRootDAO = new DmsRootDAObject(this.sessionContainer,this.dbConn);
        DmsRoot dmsRoot = (DmsRoot) dmsRootDAO.getObjectByID(this.rootId);
        this.rootType = dmsRoot.getRootType();
        this.ownerId = dmsRoot.getOwnerID();
      }
      if (this.expandId!=null) {
        DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager(this.sessionContainer,this.dbConn);
        this.expandParentIds = docRetrievalManager.getParentDocumentList(this.expandId);
        //this.expandParentIds.remove(this.expandId);
      }
      sbJstCode.append("<script type=\"text/javascript\">\n");
      sbJstCode.append("\tvar "+this.name+" = new dTree('"+this.name+"');\n");
      sbJstCode.append("\t"+this.name + ".rootType = \""+this.rootType+"\";\n");
      sbJstCode.append("\t"+this.name + ".rootId = "+this.rootId+";\n");
      sbJstCode.append("\t"+this.name + ".ownerId = "+this.ownerId+";\n");
      sbJstCode.append("\t"+this.name + ".config.usePermission = "+this.permission+";\n");
      sbJstCode.append("\t"+this.name + ".config.useCookies = "+this.cookie+";\n");
      sbJstCode.append("\t"+this.name + ".config.useCheckbox = "+this.checkbox+";\n");
      sbJstCode.append("\t"+this.name + ".config.useTextClickOpen = "+this.textClickOpen+";\n");
      sbJstCode.append("\t"+this.name + ".config.useTextClickClose = "+this.textClickClose+";\n");

      sbDivCode.append("<div class=\"dtree\">\n");
      if (this.rootStartId!=null) {
        DmsTreeController controller = new DmsTreeController(this.sessionContainer, this.dbConn);
        controller.initPermissionOnlyByParameters(this.rootType, this.rootId, this.ownerId, this.rootStartId);
        this.appendTreeCodeByRootStartId(this.rootStartId, -1, 1);
      }else {
        this.appendTreeCodeByParentId(new Integer("0"), -1, 1);
      }
      sbJstCode.append("\t</script>\n");
      sbDivCode.append("</div>\n");
    }catch (Exception ex) {
      throw ex;
    }finally {
      try {this.dbConn.close();}catch(Exception ex) {} finally {this.dbConn = null;}
    }
  }

  private void appendTreeCodeByRootStartId(Integer startId, int pNodeIndex, int level) throws Exception {
    DmsTreeController controller = new DmsTreeController(this.sessionContainer, this.dbConn);
    DmsTreeNode node = controller.getDmsTreeNode(this.rootType, this.rootId, this.ownerId, startId, this.permission);;
    if (node!=null) {
      int index = this.nodeIndex ++;
      Integer id   = node.getId();
      Integer pid  = node.getParentId();
      String  name = node.getDocumentName();
      String type  = node.getDocumentType();
      boolean isHasChildren = node.isHasChildren();
      boolean isLastNode = true;
      boolean isOpen = isHasChildren;
      boolean isInit = isHasChildren;

      sbJstCode.append("\t"+this.name + ".add("+index+","+pNodeIndex+"," + id + "," + pid +",\""+name.replaceAll("\"","\\\\\"")+ "\",'"+ type +"'," + level + "," + isHasChildren + "," + isLastNode + "," + isOpen + ","+isInit+");\n");
      sbDivCode.append("<div class=\"dTreeNode\">\n");
      this.getIndent(index, id, level, type, isHasChildren, isLastNode, isOpen);
      this.aIndent[level] = isLastNode;
      String cssClassName = null;
      if (this.expandId!=null && this.expandId.equals(id)) {
        cssClassName = "nodeSel";
        sbJstCode.append("\t"+this.name + ".sNodeIndex = "+index+";\n");
      }else {
        cssClassName = "node";
      }
      sbDivCode.append("&nbsp;<a id=\"s"+this.name+index+"\" class=\""+cssClassName+"\" href=\"javascript:"+this.name+".s("+index+");\">"+name+"</a>\n");
      sbDivCode.append("</div>\n");

      if (isHasChildren && isInit) {
        sbDivCode.append("<div id=\"d"+this.name+index+"\" class=\"clip\" style=\"display:block;\">\n");
        this.appendTreeCodeByParentId(id, index, level+1);
        sbDivCode.append("</div>\n");
      }else if (isHasChildren) {
        sbDivCode.append("<div id=\"d"+this.name+index+"\" class=\"clip\" style=\"display:none;\"></div>\n");
      }
    }
  }

  private void appendTreeCodeByParentId(Integer parentId, int pNodeIndex, int level) throws Exception {
    DmsTreeController controller = new DmsTreeController(this.sessionContainer, this.dbConn);
    List lTreeNodes = controller.getDmsTreeNodeListByParameter(this.rootType, this.rootId, this.ownerId, parentId, this.permission);;
    for (int i=0; i<lTreeNodes.size(); i++) {
      DmsTreeNode node = (DmsTreeNode)lTreeNodes.get(i);
      int index = this.nodeIndex ++;
      Integer id = node.getId();
      Integer pid = node.getParentId();
      String  name = node.getDocumentName();
      String type = node.getDocumentType();
      DocumentRetrievalManager documentRetrievalManager = new DocumentRetrievalManager(sessionContainer,dbConn);
      DocumentValidateManager documentValidateManager = new DocumentValidateManager(sessionContainer,dbConn);
      DmsDocument doc = documentRetrievalManager.getDocumentByID(id);
      boolean isExpire = documentValidateManager.checkExpireDocumentOwnerStatus(doc);
      boolean isHasChildren = node.isHasChildren();
      if(isExpire){
      	isHasChildren = false;
      }
      boolean isLastNode = ((i+1)==lTreeNodes.size());
      boolean isOpen = isHasChildren && (level<2 || this.expandParentIds.contains(id) || (this.cookie.equals("true") && this.coOpenIds.indexOf("."+id+".")!=-1));
      boolean isInit = isOpen;

      sbJstCode.append("\t"+this.name + ".add("+index+","+pNodeIndex+"," + id + "," + pid +",\""+name.replaceAll("\"","\\\\\"")+ "\",'"+ type +"'," + level + "," + isHasChildren + "," + isLastNode + "," + isOpen + ","+isInit+");\n");
      sbDivCode.append("<div class=\"dTreeNode\">\n");
      this.getIndent(index, id, level, type, isHasChildren, isLastNode, isOpen);
      this.aIndent[level] = isLastNode;
      String cssClassName = null;
      if (this.expandId!=null && this.expandId.equals(id)) {
        cssClassName = "nodeSel";
        sbJstCode.append("\t"+this.name + ".sNodeIndex = "+index+";\n");
      //}else if (this.coCheckId!=null && this.coCheckId.equals(id.toString())) {
      //  cssClassName = "nodeSel";
      }else {
        cssClassName = "node";
      }
      if(isExpire){
      	sbDivCode.append("&nbsp;"+name+"\n");
      }else{
      	sbDivCode.append("&nbsp;<a id=\"s"+this.name+index+"\" class=\""+cssClassName+"\" href=\"javascript:"+this.name+".s("+index+");\">"+name+"</a>\n");
      }
      sbDivCode.append("</div>\n");

      if (isHasChildren && isInit) {
        sbDivCode.append("<div id=\"d"+this.name+index+"\" class=\"clip\" style=\"display:block;\">\n");
        this.appendTreeCodeByParentId(id, index, level+1);
        sbDivCode.append("</div>\n");
      }else if (isHasChildren) {
        sbDivCode.append("<div id=\"d"+this.name+index+"\" class=\"clip\" style=\"display:none;\"></div>\n");
      }
    }
  }

  private void getIndent(int index, Integer id, int level, String type, boolean isHasChildren, boolean isLastNode, boolean isOpen) throws Exception {
    for (int n =2; n<level; n++) {
      sbDivCode.append("<img src=\"" + ( this.aIndent[n] ? mImageIcon.get("empty") : mImageIcon.get("line")) + "\" align=\"absmiddle\" border=\"0\" alt=\"\" />");
    }
    if (level>1) {
      String joinIcon = isHasChildren ?
          (isLastNode ? ((isOpen?(String)mImageIcon.get("minusbottom"):(String)mImageIcon.get("plusbottom"))) : (isOpen?(String)mImageIcon.get("minus"):(String)mImageIcon.get("plus"))) :
          (isLastNode ? (String)mImageIcon.get("joinbottom") : (String)mImageIcon.get("join"));
      if (isHasChildren) {
        sbDivCode.append("<a href=\"javascript:"+this.name+".o("+index+");\" style=\"cursor:pointer;\">");
      }
      sbDivCode.append("<img id=\"j" + this.name+index+"\" class=\"join\" src=\"" + joinIcon + "\" align=\"absmiddle\" border=\"0\" alt=\"\">");
      if (isHasChildren) {
        sbDivCode.append("</a>");
      }
    }
    String foldIcon = "";
    if (level==1) {
      foldIcon = isOpen ? (String)mImageIcon.get("rootOpen") : (String)mImageIcon.get("root");
      sbDivCode.append("<img id=\"i"+this.name+index+"\" src=\""+ foldIcon+ "\" align=\"absmiddle\" border=\"0\" alt=\"\">");
    }else {
      if (type.equals(DmsDocument.FOLDER_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("folderOpen"): (String)mImageIcon.get("folder");
      }else if (type.equals(DmsDocument.COMPOUND_DOC_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("compoundOpen"): (String)mImageIcon.get("compound");
      }else if (type.equals(DmsDocument.PAPER_DOC_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("paperOpen") : (String)mImageIcon.get("paper");
      }else if (type.equals(DmsDocument.EMAIL_DOC_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("emailOpen") : (String)mImageIcon.get("email");
      }else if (type.equals(DmsDocument.FORM_DOC_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("formOpen") : (String)mImageIcon.get("form");
      }else if (type.equals(DmsDocument.FLOW_DOC_TYPE)) {
        foldIcon = isOpen ? (String)mImageIcon.get("workflowOpen") : (String)mImageIcon.get("workflow");
      }else if (type.equals(DmsDocument.DOCUMENT_LINK)) {
        foldIcon = (String)mImageIcon.get("shortcut");
      }else if (type.equals(DmsDocument.DOCUMENT_TYPE)) {
        foldIcon = (String)mImageIcon.get("file");
      }
      sbDivCode.append("<img id=\"i"+this.name+index+"\" src=\""+ foldIcon+ "\" align=\"absmiddle\" border=\"0\" alt=\"\">");
    }
    if (this.checkbox.equals("true")) {
      sbDivCode.append("<input type=\"checkbox\" id=\"c"+this.name+index+"\" name=\"dmsDocsID\" value=\""+ id+ "\" class=\"checkbox\" onclick=\"javascript:"+this.name+".c(this, "+index+");\">");
    }
  }

  private SessionContainer getSessionContainer() {
    SessionContainer ctx = (SessionContainer)pageContext.getSession().getAttribute(GlobalConstant.SESSION_CONTAINER_KEY);
    if (ctx==null) {
      ctx = new SessionContainer();
      pageContext.getSession().setAttribute(GlobalConstant.SESSION_CONTAINER_KEY, ctx);
    }
    return(ctx);
  }

  private void setCookies(Cookie[] cookies) {
    if (cookies!=null) {
      for (int i = 0; i < cookies.length; i++) {
        if (cookies[i].getName().equals("co" + this.name)) {
          this.coOpenIds = cookies[i].getValue();
        }
        if (cookies[i].getName().equals("cs" + this.name)) {
          this.coCheckId = cookies[i].getValue();
        }
      }
    }
  }

  public void doCatch(Throwable ex) throws Throwable {
    log.error(ex, ex);
    throw new JspException(ex);
  }

  public void doFinally() {

  }

  public void release() {
    this.name = null;
    this.rootId = null;
    this.rootType = null;
    this.ownerId = null;
    this.expandId = null;
    this.permission = null;
    this.cookie = null;
    this.checkbox = null;
    this.textClickOpen = null;
    this.textClickClose = null;
  }

  public void setOwnerId(Integer ownerId) {
    this.ownerId = ownerId;
  }

  public void setOwnerId(String ownerId) {
    this.ownerId = new Integer(ownerId);
  }

  public void setRootId(Integer rootId) {
    this.rootId = rootId;
  }

  public void setRootId(String rootId) {
    this.rootId = new Integer(rootId);
  }

  public void setRootType(String rootType) {
    this.rootType = rootType;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setExpandId(Integer expandId) {
    this.expandId = expandId;
  }

  public void setExpandId(String expandId) {
    this.expandId = new Integer(expandId);
  }

  public void setRootStartId(Integer rootStartId) {
    this.rootStartId = rootStartId;
  }

  public void setRootStartId(String rootStartId) {
    this.rootStartId = new Integer(rootStartId);
  }

  public void setPermission(String permission) {
    this.permission = permission;
  }

  public void setCookie(String cookie) {
    this.cookie = cookie;
  }

  public void setCheckbox(String checkbox) {
    this.checkbox = checkbox;
  }

  public void setTextClickOpen(String textClickOpen) {
    this.textClickOpen = textClickOpen;
  }

  public void setTextClickClose(String textClickClose) {
    this.textClickClose = textClickClose;
  }

}